/**
 * 表格生成类
 */
;( function()
{
    var DataGrid = function( options )
    {
        this.table = null;
        this.thead = null;
        this.tbody = null;
        this.tfoot = null;

        this.headItem = [];
        this.bodyItem = [];
        this.footItem = [];

        this._isRowsName = null;
        this._isHeadFiexd = null;
        this._isFootFiexd = null;
        this._isRowsFiexd = null;
        this._cloneHead = null;
        this._headContainer = null;
        this._headContainerTop = null;
        this._footContainerTop = null;
        this._rowsContainer = null;
        this._rowscloneItem = null;
        this._cloneFoot = null;
        this._footContainer = null;

        this._innerWidth = window.innerWidth;
        this._innerHeight = window.innerHeight;

        if( options )
        {
            if( options["target"] )
            {
                this._target = options["target"];

                this._item = options["item"] || { c : {}, d : { h : { i : [] }, r : { i : [] } } };

                this._nullChart = options["nullChart"] || "-";

                this._fields = [];

                this._tdmouseover = typeof options.tdmouseover === "function" ? options.tdmouseover : function(){};

                this._tdmouseout = typeof options.tdmouseout === "function" ? options.tdmouseout : function(){};

                this._tdmousemove = typeof options.tdmousemove === "function" ? options.tdmousemove : function(){};

                this._tdclick = typeof options.tdclick === "function" ? options.tdclick : function(){};

                this._headThClick = typeof options.headThClick === "function" ? options.headThClick : null;

                this.initialize();
            }

            document.body.style.overflow = document.documentElement.style.overflow = "hidden";
        }
    }

    DataGrid.prototype = {

        reInitialize : function( options )
        {
            this._item = options["item"] || { c : {}, d : { h : { i : [] }, r : { i : [] } } };

            this._fields = [];

            this.table = null;
            this.thead = null;
            this.tbody = null;
            this.tfoot = null;

            this.headItem = [];
            this.bodyItem = [];
            this.footItem = [];

            this._isRowsName = null
            this._isHeadFiexd = null;
            this._isFootFiexd = null;
            this._isRowsFiexd = null;
            this._cloneHead = null;
            this._headContainer = null;
            this._headContainerTop = null;
            this._footContainerTop = null;
            this._rowsContainer = null;
            this._rowscloneItem = null;
            this._cloneFoot = null;
            this._footContainer = null;

            this.initialize();
        },

        _createTableElement : function()
        {
            var table = document.createElement("table");

            var tableConfig = this._item[ "c" ];

            if( tableConfig && tableConfig[ "i" ] )table.setAttribute("data-status",tableConfig["i"] || null );

            if( tableConfig && tableConfig[ "t" ] )table.setAttribute("data-type",tableConfig["t"] || null );

            if( tableConfig && tableConfig[ "l" ] )table.setAttribute("data-level",tableConfig["l"] || null );

            table.className = "table table-bordered table-striped table-hover";

            return table;
        },

        /** 创建表格*/
        _createTable : function()
        {
            this.table = this._createTableElement();

            this.table.style.width = "100%"; // 修改

            this._target.innerHTML = "";

            var div = document.createElement("div");

            div.id = "dataExport";

            div.appendChild( this.table );

            this._target.appendChild( div );
        },

        // 横向合并
        _setColspan : function( elem, value )
        {
            value && elem.setAttribute( "colspan", value );
        },

        _getScrollBarSize : function( elem )
        {
            return elem.offsetWidth - elem.clientWidth;
        },

        // 纵向合并
        _setRowspan : function( rowspanList, tag, table )
        {
            for( var i = 0, len = rowspanList.length; i < len; i += 1 )
            {
                var items = ( table || this.table ).getElementsByClassName( tag + "_" + rowspanList[ i ] );

                var ofst = null;

                var removeElem = [];

                for( var p = 0, plen = items.length; p < plen; p += 1 )
                {
                    if( p )
                    {
                        if( ofst.getAttribute("data-str") == items[ p ].getAttribute("data-str") )
                        {
                            ofst.rowSpan++;

                            removeElem.push( items[ p ] );
                        }
                        else
                        {
                            ofst = items[ p ];
                        }
                    }
                    else
                    {
                        ofst = items[ p ];
                    }
                }


                for( var n = 0, nlen = removeElem.length; n < nlen; n += 1 )
                {
                    removeElem[ n ].parentNode.removeChild( removeElem[ n ] );
                }

            }
        },

        /** 处理表头*/
        _createTableHeader : function()
        {
            var headCfg = this._item["head"] || this._item["h"] || {};

            var headItem = headCfg["item"] || headCfg["i"] || null;

            var sGroup = headCfg["group"] || headCfg["g"] || null;

            this.headItem = headItem;

            var sAxisX = headCfg["axis"] || headCfg["a"] || null;

            this.thead = document.createElement("thead");

            var oTrFrag = document.createDocumentFragment();

            if( !headItem ) return false;

            var headLen = headItem.length;

            this._isHeadFiexd = headCfg["fiexd"] || headCfg["f"] || null;

            for( var i = 0, tr; tr = headItem[ i ]; i += 1 )
            {
                var oTr = document.createElement("tr");

                var oTdFrag = document.createDocumentFragment();

                for( var p = 0, d; d = tr[ p ]; p += 1 )
                {
                    var oth = document.createElement("th");

                    var field =  oth._field = d["field"] || d["f"] || null;

                    oth.className = "h_" + field;

                    this._setColspan( oth, d["colspan"] || d["c"] );

                    var sTitle = d["title"] || d["t"];

                    var sid = d["id"] || d["i"];

                    oth.setAttribute( "data-str", sTitle || "" );

                    oth.setAttribute( "data-id", sid || "" );

//                    console.log( sAxisX );

                    if( sAxisX instanceof Array && sAxisX.length ){

                        oth.setAttribute( "data-axis", sAxisX[ i ] || "" );

                        (sAxisX[ i ]=="LPMC")&&(oth.className += " xcase");
                    };

                    oth.innerHTML = sTitle || this._nullChart;

                    oTdFrag.appendChild( oth );

                    if( i  == headLen - 1 )
                    {
                        this._fields.push( field );

                        if( field == sGroup )
                        {
                            /*var caret = document.createElement("span");

                            caret.className = "caret";

                            oth.appendChild( caret );*/

                            oth.className = oth.className + " grid_groud";
                        }
                    }
                }

                oTdFrag.appendChild( document.createElement("th" ) );
                oTdFrag.childNodes[ oTdFrag.childNodes.length - 1 ].style.width = "100%";

                oTr.appendChild( oTdFrag );

                oTrFrag.appendChild( oTr );
            }

            this.thead.appendChild( oTrFrag );

            this.table.appendChild( this.thead );

            this._setRowspan( headCfg["rowspan"] || headCfg["r"] || [], "h" );

            if( this._target.offsetWidth < this.table.offsetWidth ) this._removeLastTd( this.thead );
        },

        _removeLastTd : function( container )
        {
            for( var i = 0, rows = container.rows, elem; elem = rows[ i ]; i += 1 )
            {
                elem.removeChild( elem.lastChild );
            }
        },

        /** 处理表主体*/
        _createTableBody : function()
        {
            var sType = this._item["type"] || this._item["t"] || null;

            var bodyCfg = this._item["rows"] || this._item["r"] || {};

            var sAxisY = bodyCfg["axis"] || bodyCfg["a"] || null;

            var bodyItem = bodyCfg["item"] || bodyCfg["i"] || null;

            var sGroup = bodyCfg["group"] || bodyCfg["g"] || null;

            this.bodyItem = bodyItem;

            this.tbody = document.createElement("tbody");

            var oTrFrag = document.createDocumentFragment();

            if( !bodyItem ) return false;

            this._isRowsName = bodyCfg["headname"] || bodyCfg["h"] || null;

            this._isRowsFiexd = bodyCfg["fiexd"] || bodyCfg["f"] || null;

            var isFiexd = this._isRowsFiexd && this._isRowsFiexd.length;

            if( isFiexd ) this._rowscloneItem = document.createDocumentFragment();

            var oCloneTr = null;

            var oCloneoTdFrag = null;

            for( var i = 0, tr; tr = bodyItem[ i ]; i += 1 )
            {
                var oTr = document.createElement("tr");

                if( isFiexd ) oCloneTr = oTr.cloneNode( true );

                var oTdFrag = document.createDocumentFragment();

                if( isFiexd ) oCloneoTdFrag = document.createDocumentFragment();

                for( var n = 0, nlen = this._fields.length; n < nlen; n += 1 )
                {
                    var oCloneTd = null;

                    var isTd = this._isRowsName.indexOf( this._fields[ n ] ) == -1;

                    var otd = document.createElement( isTd ? "td" : "th" );

                    otd._trIndex = i;

                    otd.className = "b_" + this._fields[ n ];

                    if( this._fields[ n ] =="LPMC" ){

                        otd.className+=" xcase";
                    }

                    if( sGroup == this._fields[ n ] )
                    {
                        otd.className = otd.className + " grid_groud";
                    }

                    var sTitle = tr[ this._fields[ n ] ];

                    if( isTd )
                    {
                        otd.setAttribute( "data-type", sType || "" );
                    }
                    else
                    {
                        var sId = tr[ "id" ] || tr[ "i" ];

                        otd.setAttribute( "data-id", sId || "" );

                        otd.setAttribute( "data-axis", sAxisY || "" );
                    }

                    otd.setAttribute( "data-str", sTitle || "" ); 

                    otd.innerHTML = (sTitle==undefined)? this._nullChart:sTitle;

                    oTdFrag.appendChild( otd );

                    if( isFiexd ) oCloneTd = this._isRowsFiexd.indexOf( this._fields[ n ] ) == -1 ? null : otd.cloneNode( true );

                    if( isFiexd && oCloneTd ) oCloneoTdFrag.appendChild( oCloneTd );
                }

                if( isFiexd ) oCloneTr.appendChild( oCloneoTdFrag );

                oTdFrag.appendChild( document.createElement( isTd ? "td" : "th" ) );

                oTr.appendChild( oTdFrag );

                oTrFrag.appendChild( oTr );

                if( isFiexd ) this._rowscloneItem.appendChild( oCloneTr.cloneNode( true ) );
            }

            this.tbody.appendChild( oTrFrag );

            this.table.appendChild( this.tbody );

            this._setRowspan( bodyCfg["rowspan"] || bodyCfg["r"] || [], "b" );

            if( this._target.offsetWidth < this.table.offsetWidth ) this._removeLastTd( this.tbody );
        },

        /** 处理表尾部*/
        _createTableFooter : function()
        {
            var footCfg = this._item["foot"] || this._item["f"] || {};

            var footItem = footCfg["item"] || footCfg["i"] || null;

            var sGroup = footCfg["group"] || footCfg["g"] || null;

            this.footItem = footItem;

            this.tfoot = document.createElement("tfoot");

            var oTrFrag = document.createDocumentFragment();

            if( !footItem ) return false;

            this._isFootFiexd = footCfg["fiexd"] || footCfg["f"] || 0;

            for( var i = 0, tr; tr = footItem[ i ]; i += 1 )
            {
                var oTr = document.createElement("tr");

                var oTdFrag = document.createDocumentFragment();

                for( var p = 0, d; d = tr[ p ]; p += 1 )
                {
                    var otd = document.createElement("th");

                    var r = footItem[ i ][ p ];

                    if( this._fields.indexOf( r["field"] || r["f"] ) < 0 ) continue;

                    otd.className = "f_" + ( r["field"] || r["f"]);

                    var sTitle = r["title"] || r["t"];

                    otd.innerHTML = sTitle || this._nullChart;

                    otd.style["text-align"] = "center";

                    this._setColspan( otd, r["colspan"] || r["c"] );

                    oTdFrag.appendChild( otd );
                }

                oTdFrag.appendChild( document.createElement("th" ) );

                oTr.appendChild( oTdFrag );

                oTrFrag.appendChild( oTr );
            }

            this.tfoot.appendChild( oTrFrag );

            this.table.appendChild( this.tfoot );

            this._setRowspan( footCfg["rowspan"] || footCfg["r"] || [], "f" );

            if( this._target.offsetWidth < this.table.offsetWidth ) this._removeLastTd( this.tfoot );
        },

        _setTargetSize : function()
        {
            this._target.style.overflow = "auto";
        },

        _setTdHeadWidth : function()
        {
            if( !this._cloneHead ) return false;

            var trs = this.thead.childNodes;

            var cloneTrs = this._cloneHead.childNodes;

            var newTrs = this._headContainerTop && this._headContainerTop.getElementsByTagName("thead")[ 0 ].childNodes;

            for( var i = 0, tr; tr = trs[ i ]; i += 1 )
            {
                var tds = tr.childNodes;

                var cloneTds = cloneTrs[ i ].childNodes;

                var newTds = newTrs && newTrs[ i ].childNodes;

                for( var p = 0, td; td = tds[ p ]; p += 1 )
                {
                    cloneTds[ p ].style.width = td.offsetWidth + "px";

                    if( newTds && newTds[ p ] )
                    {
                        if( newTds[ p ].className == cloneTds[ p ].className )
                        {
                            newTds[ p ].style.width = cloneTds[ p ].style.width;
                        }
                    }

                }
            }

            this._innerWidth = window.innerWidth;

            this._innerHeight = window.innerHeight;

            this._headContainer.style.width = ( this._innerWidth - this._getScrollBarSize( this._target ) ) + "px";

            this._headContainer.style.overflow = "hidden";

            this._headContainer.childNodes[ 0 ].style.width = this.table.offsetWidth + "px"; //  + 20

            this._setTargetSize();
        },

        _setTdFootWidth : function()
        {
            if( !this._cloneFoot ) return false;

            var trs = this.tfoot.childNodes;

            var cloneTrs = this._cloneFoot.childNodes;

            for( var i = 0, tr; tr = trs[ i ]; i += 1 )
            {
                var tds = tr.childNodes;
                var cloneTds = cloneTrs[ i ].childNodes;

                for( var p = 0, td; td = tds[ p ]; p += 1 )
                {
                    cloneTds[ p ].style.width = td.offsetWidth + "px";
                }
            }

            var offsetX = this.tfoot.offsetLeft;

            var offsetY = 0;

            if( this.table.offsetHeight <=  this._target.offsetHeight )
            {
                offsetY = this.tfoot.offsetTop + this._target.offsetTop;
            }
            else
            {
                offsetY = this._innerHeight - this.tfoot.offsetHeight - ( this.table.offsetWidth <= this._target.offsetWidth ? 0 : this._getScrollBarSize( this._target ) );
            }

            this._footContainer.style.cssText = "position:fixed;left:" + offsetX + "px;top:" + offsetY + "px;z-index:2;";

            this._innerWidth = window.innerWidth;

            this._innerHeight = window.innerHeight;

            this._footContainer.style.width = ( this._innerWidth - this._getScrollBarSize( this._target ) ) + "px";

            this._footContainer.style.overflow = "hidden";

            this._footContainer.childNodes[ 0 ].style.width = this.table.offsetWidth + "px"; //  + 20

            if( this._footContainerTop ) this._footContainerTop.style.cssText = "position:fixed;left:" + offsetX + "px;top:" + ( offsetY + 1 ) + "px;z-index:3;";

        },

        _setTdRowsHeight : function()
        {
            if( !this._rowsContainer ) return false;

            var Height = this._innerHeight - ( this.table.offsetWidth <= this._target.offsetWidth ? 0 : this._getScrollBarSize( this._target ) ) - this.thead.offsetHeight - this._target.offsetTop;

            this._rowsContainer.style.height = this.table.offsetHeight <=  this._target.offsetHeight ? "auto" : Height + "px";

            this._rowsContainer.style.overflow = "hidden";
        },

        _setTdRowsWidth : function()
        {
            var trs = this.tbody.childNodes;

            if( !this._rowsContainer ) return false;

            var cloneTrs = this._rowsContainer.getElementsByTagName("tbody")[ 0 ].childNodes;

            for( var i = 0, tr; tr = cloneTrs[ i ]; i += 1 )
            {
                var cloneTds = tr.childNodes;

                var tds = trs[ i ].childNodes;

                for( var p = 0, td; td = cloneTds[ p ]; p += 1 )
                {
                    td.style.width = tds[ p ].offsetWidth + "px";
                }

                break;
            }

        },

        _getStyle : function( obj, attr )
        {
            return obj.currentStyle ? attr === "opacity" ? obj.currentStyle[ "filter" ] === "" ? 1 : ( Number( obj.currentStyle[ "filter" ].match(/\d+/g)[0] )/100 ).toString() : obj.currentStyle[ attr ] : getComputedStyle( obj, false )[ attr ];
        },

        _setFootFiexd : function()
        {
            var clone = this._cloneFoot = this.tfoot.cloneNode( true );

            this._footContainer = document.createElement("div");

            var wrap = document.createElement("div");

            wrap.appendChild( clone );

            wrap.id = "datagridFoot";

            var table = this._createTableElement();

            table.appendChild( clone );

            wrap.appendChild( table );

            this._footContainer.appendChild( wrap );

            this._target.appendChild( this._footContainer );

            this._setTdFootWidth();

            this._footContainerTop = document.createElement("div");

            var wrap2 = document.createElement("div");

            var table2 = this._createTableElement();

            var oThead = document.createElement("thead");

            var newTrs = this._footContainer.getElementsByTagName("tfoot")[ 0 ].childNodes;

            for( var i = 0, tr; tr = newTrs[ i ]; i += 1 )
            {
                var newTds = tr.childNodes;

                var oTr = document.createElement("tr");

                for( var p = 0, td; td = newTds[ p ]; p += 1 )
                {
                    if( this._isFootFiexd.indexOf( td.className.substring( 2 ) ) != -1 )
                    {
                        var clone = td.cloneNode( true );

                        //clone.style.height = ( td.offsetHeight - 1 ) + "px";

                        oTr.appendChild( clone );
                    }
                }

                oThead.appendChild( oTr );
            }

            table2.appendChild( oThead );

            wrap2.appendChild( table2 );

            this._footContainerTop.appendChild( wrap2 );

            this._target.appendChild( this._footContainerTop );

            var offsetX = this.tfoot.offsetLeft;

            var offsetY = 0;

            if( this.table.offsetHeight <=  this._target.offsetHeight )
            {
                offsetY = this.tfoot.offsetTop + this._target.offsetTop;
            }
            else
            {
                offsetY = this._innerHeight - this.tfoot.offsetHeight - ( this.table.offsetWidth <= this._target.offsetWidth ? 0 : this._getScrollBarSize( this._target ) );
            }


            this._footContainerTop.style.cssText = "position:fixed;left:" + offsetX + "px;top:" + ( offsetY + 1 ) + "px;z-index:3;";

        },

        _getOffset : function( elem )
        {
            if( !elem ) return { left : 0, top : 0 };

            var top = 0;
            var left = 0;

            while( elem.nodeName !== "HTML" )
            {
                top += elem.offsetTop;

                left += elem.offsetLeft;

                elem = elem.parentNode;
            };

            return {
                top : top,
                left : left
            };
        },

        _setHeadFiexd : function()
        {
            var offsetX = this._target.offsetLeft;

            var offsetY = this._target.offsetTop;

            var clone = this._cloneHead = this.thead.cloneNode( true );

            if( this._headThClick )
            {
                var trs = clone.childNodes;

                for( var n = 0, el; el = trs[ n ]; n += 1 )
                {
                    if( n == trs.length - 1 )
                    {
                        for( var p = 0,th; th = el.childNodes[ p ]; p += 1 )
                        {
                            th.currentObj = this;

                            th.onclick = this._headThClick;
                        }
                    }
                }
            }


            this._headContainer = document.createElement("div");

            var wrap = document.createElement("div");

            wrap.id = "datagridHead";

            wrap.appendChild( clone );

            this._headContainer.style.cssText = "position:fixed;left:" + offsetX + "px;top:" + offsetY + "px;z-index:2;";

            var table = this._createTableElement();

            table.appendChild( clone );

            wrap.appendChild( table );

            this._headContainer.appendChild( wrap );

            this._setTdHeadWidth();

            this._target.appendChild( this._headContainer );

            this._headContainerTop = document.createElement("div");

            var wrap2 = document.createElement("div");

            this._headContainerTop.style.cssText = "position:fixed;left:" + offsetX + "px;top:" + offsetY + "px;z-index:3;";

            var table2 = this._createTableElement();

            var oThead = document.createElement("thead");

            var newTrs = this._headContainer.getElementsByTagName("thead")[ 0 ].rows;

            for( var i = 0, tr; tr = newTrs[ i ]; i += 1 )
            {
                var newTds = tr.cells;

                var oTr = document.createElement("tr");

                for( var p = 0, td; td = newTds[ p ]; p += 1 )
                {
                    if( this._isHeadFiexd.indexOf( td.className.substring( 2 ) ) != -1 )
                    {
                        var cloneTd = td.cloneNode( true );

                        cloneTd.style.height = td.offsetHeight + "px";

                        oTr.appendChild( cloneTd );
                    }
                }

                oThead.appendChild( oTr );
            }

            table2.appendChild( oThead );

            wrap2.appendChild( table2 );

            this._headContainerTop.appendChild( wrap2 );

            this._target.appendChild( this._headContainerTop );
        },

        _setRowsFiexd : function()
        {

            if( !this._rowscloneItem ) return false;

            var offsetX = this._target.offsetLeft;

            var offsetY = this._target.offsetTop + this.thead.offsetHeight;

            var table = this._createTableElement();

            var tbody = document.createElement("tbody");

            tbody.appendChild( this._rowscloneItem );

            table.appendChild( tbody );

            this._rowsContainer = document.createElement("div");

            var wrap = document.createElement("div");

            wrap.id = "datagridBody";

            this._rowsContainer.style.cssText = "position:fixed;left:" + offsetX + "px;top:" + offsetY + "px;z-index:1;";

            wrap.appendChild( table );

            this._rowsContainer.appendChild( wrap );

            this._target.appendChild( this._rowsContainer );

            var bodyCfg = this._item["rows"] || this._item["r"] || {};

            this._setRowspan( bodyCfg["rowspan"] || bodyCfg["r"] || [], "b", table );

            this._setTdRowsHeight();

            this._setTdRowsWidth();

        },

        _setFixed : function()
        {
            this._setTargetSize();

            if( this._isHeadFiexd ) this._setHeadFiexd();
            if( this._isRowsFiexd ) this._setRowsFiexd();
            if( this._isFootFiexd ) this._setFootFiexd();
        },

        _scrollXHandle : function( value )
        {
            var _headItem = document.getElementById("datagridHead");

            var _footItem = document.getElementById("datagridFoot");

            if( _headItem ) _headItem.style.marginLeft = -value + "px";

            if( _footItem ) _footItem.style.marginLeft = -value + "px";
        },

        _scrollYHandle : function( value )
        {
            var _bodyItem = document.getElementById("datagridBody");

            if( _bodyItem ) _bodyItem.style.marginTop = -value + "px";
        },

        _bindEvent : function()
        {
            var self = this;

            window.addEventListener( "resize", function()
            {
                self._setTdHeadWidth();

                self._setTdRowsHeight();

                self._setTdRowsWidth();

                self._setTdFootWidth();

                return false;

            }, false );

            self._target._slt = {
                sl: self._target.scrollLeft,
                st: self._target.scrollTop
            };

            self._target.addEventListener( "scroll", function( e )
            {
                var sl = this.scrollLeft;
                var st = this.scrollTop;
                var pos = this._slt;

                if( sl != pos.sl )
                {
                    self._scrollXHandle( sl );
                }

                if( st != pos.st )
                {
                    self._scrollYHandle( st );
                }

                this._slt = {
                    sl: sl,
                    st: st
                };

                return false;

            }, false );


            var tbody = this.table.getElementsByTagName("tbody")[ 0 ];

            if( this._rowsContainer )
            {
                var tablerows = this._rowsContainer.getElementsByTagName("table")[ 0 ].rows;
            }

            if( tbody )
            {
                var tds = tbody.getElementsByTagName("td");

                for( var i = 0, td; td = tds[ i ]; i += 1 )
                {
                    td._sibhead = [];

                    td._sibrows = [];

                    if( this._headContainer )
                    {
                        var elem = this._headContainer.getElementsByClassName( "h_" + td.className.substring( 2).split(" ")[ 0 ]  );

                        td._sibhead =  elem;
                    }

                    if( this._rowsContainer )
                    {
                        for( var p = 0, tr; tr = tablerows[ p ]; p += 1 )
                        {
                            if( tr.rowIndex == td._trIndex  )
                            {
                                td._sibrows =  [ tr.childNodes[ tr.childNodes.length - 1 ] ];

                                break;
                            }
                        }
                    }
                }
            }

            window.addEventListener( "mouseover", function( e )
            {
                var oTarget = e.target;

                if( oTarget.nodeName == "TD" )
                {
                    self._addClass( oTarget._sibhead || oTarget, "tabletdhover" );

                    self._addClass( oTarget._sibrows || oTarget, "tabletdhover" );

                    self._addClass( [ oTarget ], "tabletdactive" );

                    self._tdmouseover.call( oTarget, e );
                }
            }, false );

            window.addEventListener( "mouseout", function( e )
            {
                var oTarget = e.target;

                if( oTarget.nodeName == "TD" )
                {
                    self._removeClass( oTarget._sibhead || null, "tabletdhover" );

                    self._removeClass( oTarget._sibrows || null, "tabletdhover" )

                    self._removeClass( [ oTarget ], "tabletdactive" );

                    self._tdmouseout.call( oTarget, e );
                }
            }, false );

            window.addEventListener( "mousemove", function( e )
            {
                var oTarget = e.target;

                if( oTarget.nodeName == "TD" )
                {
                    self._tdmousemove.call( oTarget, e );
                }
            }, false );

            window.addEventListener( "click", function( e )
            {
                var oTarget = e.target;

                if( oTarget.nodeName == "TD" )
                {
                    self._tdclick.call( oTarget, e, [ oTarget._sibhead ? oTarget._sibhead[ 0 ] : null, oTarget._sibrows ? oTarget._sibrows[ 0 ] : null, oTarget ] );
                }
            }, false );
        },

        _addClass : function( elem, str )
        {
            if( !elem ) return false;

            if( str && typeof str === "string" )
            {
                for( var i = 0, el; el = elem[ i ]; i += 1 )
                {
                    var className = el.className,
                        oReg = RegExp( str, "ig" );

                    if( className )
                    {
                        if( !oReg.test( className ) ) el.className += " " + str ;
                    }
                    else
                    {
                        el.className = str;
                    };
                }
            };

            return elem;
        },

        _removeClass : function( elem, str )
        {
            if( !elem ) return false;

            if( str && typeof str === "string" )
            {
                var oReg = new RegExp( "\\s{0,}\\b" + str + "\\b", "ig" );

                for( var i = 0, el; el = elem[ i ]; i += 1 )
                {
                    var className = el.className;

                    if( className )
                    {
                        el.className =  className.replace( oReg, "" );
                    }
                    else
                    {
                        el.className = "";
                    };
                }

            };

            return elem;
        },

        initialize : function()
        {
            this._createTable();
            this._createTableHeader();
            this._createTableBody();
            this._createTableFooter();
            this._setFixed();
            this._bindEvent();
            this._target.scrollTop = 0;
            this._target.scrollLeft = 0;
        }
    }

    window.DataGrid = DataGrid;
})();
